// perl_classes.h - interface with Perl

class PerlObj {
	public:
		PerlObj();
		~PerlObj();
		SV* GetPerlObj();
		void InUse(bool in_use);
		bool InUse();
	protected:
		void CreatePerlObj(const char* classname, void* ptr);
		SV* m_perl_obj;
		bool m_in_use;
};

class PerlSink {
	public:
		PerlSink();
		~PerlSink();
		void AttachPerlSink(SV* sink);
		void DetachPerlSink(SV* sink);
		void DetachAllPerlSinks();
		void ResetPerlDoc(SV* doc);
	protected:
		std::vector<SV*> m_perl_sinks;
		extensions::IDocumentPtr m_doc;
		SV* m_perl_doc;
};

// predeclare
class PerlAppEventSink;
class PerlDocumentEventSink;
class PerlTextEditorEventSink;
class PerlRecorder;

typedef boost::shared_ptr<PerlAppEventSink> PerlAppEventSinkPtr;
typedef boost::shared_ptr<PerlDocumentEventSink> PerlDocumentEventSinkPtr;
typedef boost::shared_ptr<PerlTextEditorEventSink> PerlTextEditorEventSinkPtr;
typedef boost::shared_ptr<PerlRecorder> PerlRecorderPtr;

struct TrackedDocument {
	extensions::IDocumentPtr cpp_doc;
	SV* perl_doc;
	PerlDocumentEventSinkPtr document_sink;
	PerlTextEditorEventSinkPtr text_editor_sink;
};

class PerlAppEventSink : public extensions::IAppEventSink, public PerlSink {
	public:
		PerlAppEventSink();
		virtual ~PerlAppEventSink();
		virtual void OnNewDocument(extensions::IDocumentPtr& doc);
		virtual void OnAppClose();
		virtual void OnDocSelected(extensions::IDocumentPtr& doc);
		virtual void OnFirstEditorCreated(HWND hWndScintilla);
};

class PerlDocumentEventSink : public extensions::IDocumentEventSink, public PerlSink {
	public:
		PerlDocumentEventSink(extensions::IDocumentPtr doc, SV* perl_doc);
		virtual ~PerlDocumentEventSink();
		virtual void OnSchemeChange(const char* scheme);
		virtual void OnDocClosing();
		virtual void OnAfterLoad();
		virtual void OnBeforeSave(const wchar_t* filename);
		virtual void OnAfterSave();
		virtual void OnModifiedChanged(bool modified);
		virtual void OnWriteProtectChanged(bool writeProtect);
};

class PerlTextEditorEventSink : public extensions::ITextEditorEventSink, public PerlSink {
	public:
		PerlTextEditorEventSink(extensions::IDocumentPtr doc, SV* perl_doc);
		virtual ~PerlTextEditorEventSink();
		virtual void OnCharAdded(char c);
		char* GetLastAnsiCharAsUtf8(int pos);
		char* GetLastUtf8CharAsUtf8(int pos);
		char* GetLastDBCSCharAsUtf8(int pos, int cp);
		char* GetLastCharAsUtf8(int pos);
};

class PerlDocumentTracker {
	public:
		PerlDocumentTracker();
		~PerlDocumentTracker();
		bool Add(extensions::IDocumentPtr doc, TrackedDocument** tdoc);
		TrackedDocument* Fetch(extensions::IDocumentPtr doc);
		void Remove(extensions::IDocumentPtr doc);
		void Blank();
		void Reset();
		AV* PerlArray();
		int Count();
	private:
		std::vector<TrackedDocument*> m_tracked_documents;
};

class PerlMenu : public extensions::IMenuItems, public PerlObj {
	public:
		PerlMenu(const char* classname, extensions::cookie_t cookie);
		virtual ~PerlMenu();
		virtual int GetItemCount() const;
		virtual const extensions::MenuItem& GetItem(int index) const;
		extensions::cookie_t GetCookie();
	private:
		extensions::cookie_t m_cookie;
};

void PerlMenuHandler(extensions::cookie_t cookie);

struct TrackedMenu {
	extensions::cookie_t cookie;
	PerlMenu* menu;
};

class PerlMenuTracker {
	public:
		PerlMenuTracker();
		~PerlMenuTracker();
		bool Add(PerlMenu* menu);
		TrackedMenu* Fetch(extensions::cookie_t cookie);
		void Blank();
	private:
		std::vector<TrackedMenu*> m_tracked_menus;
};

struct TrackedMenuItem {
	extensions::MenuItem* menuitem;
	SV* hashref;
};

class PerlMenuItemTracker {
	public:
		PerlMenuItemTracker();
		~PerlMenuItemTracker();
		bool Add(extensions::MenuItem* menuitem, SV* hashref);
		TrackedMenuItem* Fetch(extensions::cookie_t cookie);
		void Blank();
	private:
		std::vector<TrackedMenuItem*> m_tracked_menu_items;
};

class PerlScriptRunner : public extensions::IScriptRunner, public PerlObj {
	public:
		PerlScriptRunner(const char* classname);
		virtual ~PerlScriptRunner();
		virtual void RunScript(const char* name);
		virtual void RunDocScript(extensions::IDocumentPtr& doc);
		virtual void Eval(const char* script, PN::BaseString& output);
		virtual void Exec(const char* function, const char* param, int flags, PN::BaseString& output);
		void SetId(const char* id);
		const char* Id();
	private:
		const char* m_id;
};

class PerlScriptTracker {
	public:
		PerlScriptTracker();
		~PerlScriptTracker();
		bool Add(const char* scriptref);
		char* Fetch(const char* scriptref);
	private:
		std::vector<char*> m_tracked_refs;
};

class PerlRecorder : public extensions::IRecorder, public PerlSink {
	public:
		PerlRecorder();
		virtual ~PerlRecorder();
		virtual void RecordScintillaAction(int message, WPARAM wParam, LPARAM lParam);
		virtual void RecordSearchAction(SearchType type, const extensions::ISearchOptions* options, FindNextResult result);
		virtual void StartRecording();
		virtual void StopRecording();
};
